#include "sdk.h"
#include <wx/combo.h>
#include <wx/listbox.h>
#include <M_Code_StyledTextCtrl.h>
#include "IncrementalSearch.h"
#include "IncrementalSearchConfDlg.h"

namespace {
  PluginRegistrant<IncrementalSearch> reg( _T( "IncrementalSearch" ) );
  const int idIncSearchFocus = wxNewId();
  const int idIncSearchCombo = wxNewId();
}

class cbIncSearchComboPopUp :
  public wxListBox,
  public wxComboPopup {
  public:
    virtual bool Create( wxWindow* parent ) {
      ConfigManager* cfg = Manager::Get()->GetConfigManager( _T( "editor" ) );
      wxArrayString choices = cfg->ReadArrayString( _T( "/incremental_search/last_searched_items" ) );
      m_MaxHistoryLen = cfg->ReadInt( _T( "/incremental_search/max_items_in_history" ), 20 );
      return wxListBox::Create( parent, wxID_ANY, wxPoint( 0, 0 ), wxSize( 250, -1 ), choices, wxLB_SINGLE );
    }
    virtual wxWindow *GetControl() { return this; }
    virtual void SetStringValue( const wxString& s ) {
      if( s.Length() > 0 ) {
        int index = FindString( s );
        if( index != wxNOT_FOUND ) {
          Delete( index );
        }
        if( GetCount() >= m_MaxHistoryLen ) {
          Delete( GetCount() - 1 );
        }
        Insert( s, 0 );
        Select( 0 );
      }
    }
    virtual wxString GetStringValue() const {
      return wxListBox::GetStringSelection();
    }
    void SetMaxHistoryLen( int len ) {
      m_MaxHistoryLen = len;
      while( GetCount() > m_MaxHistoryLen ) {
        Delete( GetCount() - 1 );
      }
    }
  private:
    void OnMouseMove( wxMouseEvent& event ) {
      SetSelection( HitTest( wxPoint( event.GetX(), event.GetY() ) ) );
    }
    void OnMouseClick( M_Code_unused wxMouseEvent& event ) {
      Dismiss();
      wxCommandEvent evt( wxEVT_COMMAND_TEXT_UPDATED, idIncSearchCombo );
      Manager::Get()->GetAppFrame()->GetEventHandler()->ProcessEvent( evt );
    }
    unsigned int m_MaxHistoryLen;
    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE( cbIncSearchComboPopUp, wxListBox )
  EVT_MOTION( cbIncSearchComboPopUp::OnMouseMove )
  EVT_LEFT_UP( cbIncSearchComboPopUp::OnMouseClick )
END_EVENT_TABLE()

BEGIN_EVENT_TABLE( IncrementalSearch, M_Code_Plugin )
  EVT_MENU( idIncSearchFocus, IncrementalSearch::OnFocusToolbar )
  EVT_TOOL( XRCID( "idIncSearchClear" ), IncrementalSearch::OnClearText )
  EVT_TOOL( XRCID( "idIncSearchPrev" ), IncrementalSearch::OnSearchPrev )
  EVT_TOOL( XRCID( "idIncSearchNext" ), IncrementalSearch::OnSearchNext )
  EVT_TOOL( XRCID( "idIncSearchHighlight" ), IncrementalSearch::OnToggleHighlight )
  EVT_TOOL( XRCID( "idIncSearchSelectOnly" ), IncrementalSearch::OnToggleSelectedOnly )
  EVT_TOOL( XRCID( "idIncSearchMatchCase" ), IncrementalSearch::OnToggleMatchCase )
  EVT_TOOL( XRCID( "idIncSearchUseRegex" ), IncrementalSearch::OnToggleUseRegex )
  EVT_MENU( XRCID( "idEditPaste" ), IncrementalSearch::OnMenuEditPaste )
END_EVENT_TABLE()

IncrementalSearch::IncrementalSearch():
  m_SearchText( wxEmptyString ),
  m_textCtrlBG_Default( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ),
  m_pToolbar( 0l ),
  m_pTextCtrl( 0l ),
  m_pEditor( 0l ),
  m_NewPos( -1 ),
  m_OldPos( -1 ),
  m_SelStart( -1 ),
  m_SelEnd( -1 ),
  m_MinPos( -1 ),
  m_MaxPos( -1 ),
  m_flags( 0 ),
  m_Highlight( false ),
  m_SelectedOnly( false ),
  m_IndicFound( 21 ),
  m_IndicHighlight( 22 ),
  m_LengthFound( 0 ),
  m_LastInsertionPoint( 0 ) {
  if( !Manager::LoadResource( _T( "IncrementalSearch.zip" ) ) ) {
    NotifyMissingFile( _T( "IncrementalSearch.zip" ) );
  }
}

IncrementalSearch::~IncrementalSearch() {
}

void IncrementalSearch::OnAttach() {
  m_pEditor = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
  wxMenuBar* mbar = Manager::Get()->GetAppFrame()->GetMenuBar();
  if( mbar->FindItem( idIncSearchFocus ) ) {
    mbar->Enable( idIncSearchFocus, m_pEditor && m_pEditor->GetControl() );
  }
  Manager::Get()->RegisterEventSink( cbEVT_EDITOR_ACTIVATED, new cbEventFunctor<IncrementalSearch, CodeBlocksEvent>( this, &IncrementalSearch::OnEditorEvent ) );
  Manager::Get()->RegisterEventSink( cbEVT_EDITOR_DEACTIVATED, new cbEventFunctor<IncrementalSearch, CodeBlocksEvent>( this, &IncrementalSearch::OnEditorEvent ) );
  Manager::Get()->RegisterEventSink( cbEVT_EDITOR_OPEN, new cbEventFunctor<IncrementalSearch, CodeBlocksEvent>( this, &IncrementalSearch::OnEditorEvent ) );
  Manager::Get()->RegisterEventSink( cbEVT_EDITOR_CLOSE, new cbEventFunctor<IncrementalSearch, CodeBlocksEvent>( this, &IncrementalSearch::OnEditorEvent ) );
  ConfigManager* cfg = Manager::Get()->GetConfigManager( _T( "editor" ) );
  int sel = -1;
  sel = cfg->ReadInt( _T( "/incremental_search/highlight_default_state" ), 0 );
  m_Highlight = ( sel == 1 ) || ( ( sel == 2 ) && cfg->ReadBool( _T( "/incremental_search/highlight_all_occurrences" ), false ) );
  sel = cfg->ReadInt( _T( "/incremental_search/selected_default_state" ), 0 );
  m_SelectedOnly = ( sel == 1 ) || ( ( sel == 2 ) && cfg->ReadBool( _T( "/incremental_search/search_selected_only" ), false ) );
  sel = cfg->ReadInt( _T( "/incremental_search/match_case_default_state" ), 0 );
  m_flags |= ( ( sel == 1 ) || ( ( sel == 2 ) && cfg->ReadInt( _T( "/incremental_search/match_case" ), false ) ) ) ? wxSCI_FIND_MATCHCASE : 0;
  sel = cfg->ReadInt( _T( "/incremental_search/regex_default_state" ), 0 );
  m_flags |= ( ( sel == 1 ) || ( ( sel == 2 ) && cfg->ReadInt( _T( "/incremental_search/regex" ), false ) ) ) ? wxSCI_FIND_REGEXP : 0;
}

void IncrementalSearch::OnRelease( bool ) {
  ConfigManager* cfg = Manager::Get()->GetConfigManager( _T( "editor" ) );
  if( cfg->ReadInt( _T( "/incremental_search/highlight_default_state" ), 0 ) == 2 ) {
    cfg->Write( _T( "/incremental_search/highlight_all_occurrences" ), m_Highlight );
  }
  if( cfg->ReadInt( _T( "/incremental_search/selected_default_state" ), 0 ) == 2 ) {
    cfg->Write( _T( "/incremental_search/search_selected_only" ), m_SelectedOnly );
  }
  if( cfg->ReadInt( _T( "/incremental_search/match_case_default_state" ), 0 ) == 2 ) {
    cfg->Write( _T( "/incremental_search/match_case" ), m_flags & wxSCI_FIND_MATCHCASE );
  }
  if( cfg->ReadInt( _T( "/incremental_search/regex_default_state" ), 0 ) == 2 ) {
    cfg->Write( _T( "/incremental_search/regex" ), m_flags & wxSCI_FIND_REGEXP );
  }
  cfg->Write( _T( "/incremental_search/last_searched_items" ), m_pChoice->GetStrings() );
  m_pTextCtrl->Disconnect( wxEVT_KEY_DOWN );
  m_pTextCtrl->Disconnect( wxEVT_KILL_FOCUS );
}

cbConfigurationPanel* IncrementalSearch::GetConfigurationPanel( wxWindow* parent ) {
  if( !IsAttached() ) {
    return NULL;
  }
  IncrementalSearchConfDlg* cfg = new IncrementalSearchConfDlg( parent );
  return cfg;
}

void IncrementalSearch::BuildMenu( wxMenuBar* menuBar ) {
  if( !m_IsAttached || !menuBar ) {
    return;
  }
  int idx = menuBar->FindMenu( _( "查找 (&amp;R)" ) );
  if( idx != wxNOT_FOUND ) {
    wxMenu* menu = menuBar->GetMenu( idx );
    wxMenuItemList& items = menu->GetMenuItems();
    wxMenuItem* itemTmp = new wxMenuItem( menu, idIncSearchFocus, _( "增量搜索 (&I)\tCtrl-I" ),
                                          _( "将焦点设置为增量搜索输入并显示工具栏（如果隐藏）" ) );
    itemTmp->SetBitmap( wxBitmap( wxXmlResource::Get()->LoadBitmap( _T( "MenuBitmap" ) ) ) );
    size_t i = 0;
    for( i = 0; i < items.GetCount(); ++i ) {
      if( items[i]->GetLabelText( items[i]->GetItemLabelText() ) == _( "Find previous" ) ) {
        ++i;
        break;
      }
    }
    menu->Insert( i, itemTmp );
    menuBar->Enable( idIncSearchFocus, m_pEditor && m_pEditor->GetControl() );
  }
}

void IncrementalSearch::OnEditorEvent( CodeBlocksEvent& event ) {
  if( !m_pToolbar || !m_pComboCtrl || !m_pTextCtrl ) {
    event.Skip();
    return;
  }
  m_pEditor = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
  m_pComboCtrl->Enable( m_pEditor && m_pEditor->GetControl() );
  wxMenuBar* mbar = Manager::Get()->GetAppFrame()->GetMenuBar();
  mbar->Enable( idIncSearchFocus, m_pComboCtrl->IsEnabled() );
  m_pToolbar->EnableTool( XRCID( "idIncSearchClear" ), !m_SearchText.empty() );
  if( m_pComboCtrl->IsEnabled() ) {
    m_SearchText = m_pTextCtrl->GetValue();
    m_pToolbar->EnableTool( XRCID( "idIncSearchPrev" ), !m_SearchText.empty() && ( ( m_flags & wxSCI_FIND_REGEXP ) == 0 ) );
    m_pToolbar->EnableTool( XRCID( "idIncSearchNext" ), !m_SearchText.empty() );
    m_NewPos = m_pEditor->GetControl()->GetCurrentPos();
    m_OldPos = m_NewPos;
  } else {
    m_pToolbar->EnableTool( XRCID( "idIncSearchPrev" ), false );
    m_pToolbar->EnableTool( XRCID( "idIncSearchNext" ), false );
  }
  event.Skip();
}

bool IncrementalSearch::BuildToolBar( wxToolBar* toolBar ) {
  if( !m_IsAttached || !toolBar ) {
    return false;
  }
  wxXmlResource* xml_res = wxXmlResource::Get();
  wxString resPath = ConfigManager::GetDataFolder() + _T( "/IncrementalSearchToolbar.xrc" );
  xml_res->Load( resPath );
  Manager::Get()->AddonToolBar( toolBar, _T( "incremental_search_toolbar" ) );
  m_pToolbar = toolBar;
  m_pToolbar->EnableTool( XRCID( "idIncSearchClear" ), false );
  m_pToolbar->EnableTool( XRCID( "idIncSearchPrev" ), false );
  m_pToolbar->EnableTool( XRCID( "idIncSearchNext" ), false );
  m_pToolbar->SetInitialSize();
  m_pComboCtrl = new wxComboCtrl( Manager::Get()->GetMinToolbar(), idIncSearchCombo, wxEmptyString, wxDefaultPosition, wxSize( 160, -1 ), wxTE_PROCESS_ENTER );
  if( m_pComboCtrl ) {
    m_pComboCtrl->SetTextIndent( 0 );
    m_pToolbar->InsertControl( m_pToolbar->GetToolPos( XRCID( "idIncSearchClear" ) ), m_pComboCtrl );
    m_pToolbar->Realize();
    m_pTextCtrl = m_pComboCtrl->GetTextCtrl();
    if( m_pTextCtrl ) {
      m_pTextCtrl->SetWindowStyleFlag( wxTE_PROCESS_ENTER | wxTE_NOHIDESEL | wxBORDER_NONE );
      m_pChoice = new cbIncSearchComboPopUp();
      m_pComboCtrl->SetPopupControl( m_pChoice );
      m_pTextCtrl->Connect( wxEVT_KEY_DOWN, ( wxObjectEventFunction )( wxEventFunction )( wxCharEventFunction )
                            &IncrementalSearch::OnKeyDown, 0, this );
      m_pTextCtrl->Connect( wxEVT_KILL_FOCUS, ( wxObjectEventFunction )( wxEventFunction )( wxFocusEventFunction )
                            &IncrementalSearch::OnKillFocus, 0, this );
      m_pTextCtrl->Connect( wxEVT_COMMAND_TEXT_UPDATED, ( wxObjectEventFunction )( wxEventFunction )( wxCommandEventFunction )
                            &IncrementalSearch::OnTextChanged, 0, this );
      m_pTextCtrl->Connect( wxEVT_COMMAND_TEXT_ENTER, ( wxObjectEventFunction )( wxEventFunction )( wxCommandEventFunction )
                            &IncrementalSearch::OnSearchNext, 0, this );
      m_textCtrlBG_Default = m_pTextCtrl->GetBackgroundColour();
      m_pComboCtrl->Enable( m_pEditor && m_pEditor->GetControl() );
      m_pToolbar->ToggleTool( XRCID( "idIncSearchHighlight" ), m_Highlight );
      m_pToolbar->ToggleTool( XRCID( "idIncSearchSelectOnly" ), m_SelectedOnly );
      m_pToolbar->ToggleTool( XRCID( "idIncSearchMatchCase" ), m_flags & wxSCI_FIND_MATCHCASE );
      m_pToolbar->ToggleTool( XRCID( "idIncSearchUseRegex" ), m_flags & wxSCI_FIND_REGEXP );
      return true;
    }
  }
  return false;
}

void IncrementalSearch::SetMaxHistoryLen( int len ) {
  if( !m_pChoice ) {
    return;
  }
  m_pChoice->SetMaxHistoryLen( len );
}

void IncrementalSearch::OnKeyDown( wxKeyEvent& event ) {
  if( m_pTextCtrl ) {
    m_LastInsertionPoint = m_pTextCtrl->GetInsertionPoint();
  }
  if( !m_IsAttached || !m_pEditor || !m_pEditor->GetControl() ) {
    event.Skip();
    return;
  }
  if( event.GetModifiers() == wxMOD_ALT && event.GetKeyCode() == WXK_DELETE ) {
    DoClearText();
  } else if( event.GetModifiers() == wxMOD_SHIFT && event.GetKeyCode() == WXK_RETURN ) {
    if( m_pToolbar->GetToolEnabled( XRCID( "idIncSearchPrev" ) ) ) {
      DoSearchPrev();
    }
  } else if( event.GetModifiers() == wxMOD_NONE && event.GetKeyCode() == WXK_ESCAPE ) {
    M_Code_StyledTextCtrl* control = m_pEditor->GetControl();
    control->SetIndicatorCurrent( m_IndicFound );
    control->IndicatorClearRange( 0, control->GetLength() );
    control->SetIndicatorCurrent( m_IndicHighlight );
    control->IndicatorClearRange( 0, control->GetLength() );
    control->GotoPos( m_NewPos );
    if( Manager::Get()->GetConfigManager( _T( "editor" ) )->ReadBool( _T( "/incremental_search/select_found_text_on_escape" ), false ) ) {
      m_SelStart = m_NewPos;
      m_SelEnd = m_SelStart + m_LengthFound;
      m_OldPos = m_NewPos;
      control->SetSelectionVoid( m_SelStart, m_SelEnd );
    }
    control->SetFocus();
  } else {
    event.Skip();
  }
}

void IncrementalSearch::OnFocusToolbar( wxCommandEvent& ) {
  if( !m_IsAttached ) {
    return;
  }
  DoFocusToolbar();
  if( Manager::Get()->GetConfigManager( _T( "editor" ) )->ReadBool( _T( "/incremental_search/select_text_on_focus" ), false ) ) {
    m_pTextCtrl->SetSelection( -1, -1 );
  } else {
    m_pTextCtrl->SetInsertionPoint( m_LastInsertionPoint );
  }
}

void IncrementalSearch::DoFocusToolbar() {
  if( !IsWindowReallyShown( m_pToolbar ) ) {
    CodeBlocksDockEvent evt( cbEVT_SHOW_DOCK_WINDOW );
    evt.pWindow = ( wxWindow* )m_pToolbar;
    Manager::Get()->ProcessEvent( evt );
  }
  m_pTextCtrl->SetFocus();
}

void IncrementalSearch::OnToggleHighlight( wxCommandEvent& ) {
  DoToggleHighlight( m_pToolbar->GetToolState( XRCID( "idIncSearchHighlight" ) ) );
}

void IncrementalSearch::DoToggleHighlight( bool checked ) {
  m_Highlight = checked;
  if( !m_pEditor || !m_pEditor->GetControl() ) {
    return;
  }
  SearchText();
}

void IncrementalSearch::OnToggleSelectedOnly( wxCommandEvent& ) {
  DoToggleSelectedOnly( m_pToolbar->GetToolState( XRCID( "idIncSearchSelectOnly" ) ) );
}

void IncrementalSearch::DoToggleSelectedOnly( bool checked ) {
  m_SelectedOnly = checked;
  if( !m_pEditor || !m_pEditor->GetControl() ) {
    return;
  }
  SearchText();
}

void IncrementalSearch::OnToggleMatchCase( wxCommandEvent& ) {
  DoToggleMatchCase( m_pToolbar->GetToolState( XRCID( "idIncSearchMatchCase" ) ) );
}

void IncrementalSearch::DoToggleMatchCase( bool checked ) {
  if( checked ) {
    m_flags |= wxSCI_FIND_MATCHCASE;
  } else {
    m_flags &=  ~wxSCI_FIND_MATCHCASE;
  }
  if( !m_pEditor || !m_pEditor->GetControl() ) {
    return;
  }
  SearchText();
}

void IncrementalSearch::OnToggleUseRegex( wxCommandEvent& ) {
  DoToggleUseRegex( m_pToolbar->GetToolState( XRCID( "idIncSearchUseRegex" ) ) );
}

void IncrementalSearch::DoToggleUseRegex( bool checked ) {
  if( checked ) {
    m_flags |= wxSCI_FIND_REGEXP;
  } else {
    m_flags &=  ~wxSCI_FIND_REGEXP;
  }
  if( !m_pEditor || !m_pEditor->GetControl() ) {
    return;
  }
  SearchText();
}

void IncrementalSearch::OnTextChanged( wxCommandEvent& ) {
  if( !m_pEditor || !m_pEditor->GetControl() ) {
    return;
  }
  SearchText();
}

void IncrementalSearch::OnKillFocus( wxCommandEvent& ) {
  if( m_pTextCtrl ) {
    m_LastInsertionPoint = m_pTextCtrl->GetInsertionPoint();
  }
}

void IncrementalSearch::VerifyPosition() {
  if( !m_pEditor || !m_pEditor->GetControl() ) {
    return;
  }
  M_Code_StyledTextCtrl* control = m_pEditor->GetControl();
  m_SelStart = control->GetSelectionStart();
  m_SelEnd = control->GetSelectionEnd();
  if( m_OldPos != m_SelEnd ) {
    m_OldPos = m_SelEnd;
    m_NewPos = m_SelEnd;
  }
}

void IncrementalSearch::SetRange() {
  if( !m_pEditor || !m_pEditor->GetControl() ) {
    return;
  }
  if( m_SelectedOnly ) {
    m_MinPos = m_SelStart;
    m_MaxPos = m_SelEnd;
  } else {
    m_MinPos = 0;
    m_MaxPos = m_pEditor->GetControl()->GetLength();
  }
  m_NewPos = std::min( m_NewPos, m_MaxPos );
  m_NewPos = std::max( m_NewPos, m_MinPos );
}

void IncrementalSearch::SearchText() {
  m_SearchText = m_pTextCtrl->GetValue();
  VerifyPosition();
  SetRange();
  if( !m_SearchText.empty() ) {
    m_pToolbar->EnableTool( XRCID( "idIncSearchClear" ), true );
    m_pToolbar->EnableTool( XRCID( "idIncSearchPrev" ), ( m_flags & wxSCI_FIND_REGEXP ) == 0 );
    m_pToolbar->EnableTool( XRCID( "idIncSearchNext" ), true );
    m_pChoice->SetStringValue( m_SearchText );
    DoSearch( m_NewPos );
  } else {
    m_pToolbar->EnableTool( XRCID( "idIncSearchClear" ), false );
    m_pToolbar->EnableTool( XRCID( "idIncSearchPrev" ), false );
    m_pToolbar->EnableTool( XRCID( "idIncSearchNext" ), false );
    m_pTextCtrl->SetBackgroundColour( m_textCtrlBG_Default );
  }
  HighlightText();
}

void IncrementalSearch::OnClearText( wxCommandEvent& ) {
  DoClearText();
}

void IncrementalSearch::DoClearText() {
  m_pTextCtrl->Clear();
  SearchText();
}

void IncrementalSearch::OnSearchPrev( wxCommandEvent& ) {
  DoSearchPrev();
}

void IncrementalSearch::DoSearchPrev() {
  VerifyPosition();
  SetRange();
  DoSearch( m_NewPos + m_LengthFound - 1, m_MaxPos, m_MinPos );
  HighlightText();
}

void IncrementalSearch::OnSearchNext( wxCommandEvent& ) {
  DoSearchNext();
}

void IncrementalSearch::DoSearchNext() {
  VerifyPosition();
  SetRange();
  DoSearch( m_NewPos + 1, m_MinPos, m_MaxPos );
  HighlightText();
}

static void SetupIndicator( M_Code_StyledTextCtrl *control, int indicator, const wxColor &colour ) {
  control->IndicatorSetForeground( indicator, colour );
  control->IndicatorSetStyle( indicator, wxSCI_INDIC_ROUNDBOX );
  control->IndicatorSetAlpha( indicator, 100 );
  control->IndicatorSetOutlineAlpha( indicator, 255 );
  #ifndef wxHAVE_RAW_BITMAP
  control->IndicatorSetUnder( indicator, true );
  #endif
  control->SetIndicatorCurrent( indicator );
}

void IncrementalSearch::HighlightText() {
  if( !m_pEditor || !m_pEditor->GetControl() ) {
    return;
  }
  M_Code_StyledTextCtrl* control = m_pEditor->GetControl();
  control->SetIndicatorCurrent( m_IndicFound );
  control->IndicatorClearRange( 0, control->GetLength() );
  control->SetIndicatorCurrent( m_IndicHighlight );
  control->IndicatorClearRange( 0, control->GetLength() );
  if( m_NewPos != wxSCI_INVALID_POSITION && !m_SearchText.empty() ) {
    ConfigManager* cfg = Manager::Get()->GetConfigManager( _T( "editor" ) );
    wxColour colourTextFound( cfg->ReadColour( _T( "/incremental_search/text_found_colour" ), wxColour( 160, 32, 240 ) ) );
    if( cfg->ReadBool( _T( "/incremental_search/center_found_text_on_screen" ), true ) ) {
      int line = control->LineFromPosition( m_NewPos );
      int onScreen = control->LinesOnScreen() >> 1;
      int l1 = line - onScreen;
      int l2 = line + onScreen;
      for( int l = l1; l <= l2; l += 2 ) {
        control->EnsureVisible( l );
      }
      control->GotoLine( l1 );
      control->GotoLine( l2 );
    }
    control->GotoPos( m_NewPos + m_SearchText.length() );
    control->EnsureCaretVisible();
    control->GotoPos( m_NewPos );
    control->SearchAnchor();
    M_Code_StyledTextCtrl* ctrlLeft = m_pEditor->GetLeftSplitViewControl();
    SetupIndicator( ctrlLeft, m_IndicFound, colourTextFound );
    M_Code_StyledTextCtrl* ctrlRight = m_pEditor->GetRightSplitViewControl();
    if( ctrlRight ) {
      SetupIndicator( ctrlRight, m_IndicFound, colourTextFound );
    }
    control->IndicatorFillRange( m_NewPos, m_LengthFound );
    if( m_Highlight ) {
      wxColour colourTextHighlight( cfg->ReadColour( _T( "/incremental_search/highlight_colour" ), wxColour( 255, 165, 0 ) ) );
      SetupIndicator( ctrlLeft, m_IndicHighlight, colourTextHighlight );
      if( ctrlRight ) {
        SetupIndicator( ctrlRight, m_IndicHighlight, colourTextHighlight );
      }
      int actualLength = 0;
      for( int pos = control->FindText( m_MinPos, m_MaxPos, m_SearchText, m_flags, &actualLength );
           pos != wxSCI_INVALID_POSITION && actualLength > 0;
           pos = control->FindText( pos += 1, m_MaxPos, m_SearchText, m_flags, &actualLength ) ) {
        if( pos > ( m_NewPos + m_LengthFound ) || pos < m_NewPos ) {
          control->EnsureVisible( control->LineFromPosition( pos ) );
          control->IndicatorFillRange( pos, actualLength );
        }
      }
    }
  }
  control->SetAnchor( m_SelStart );
  control->SetCurrentPos( m_SelEnd );
  DoFocusToolbar();
}

void IncrementalSearch::DoSearch( int fromPos, int startPos, int endPos ) {
  if( !m_pEditor || !m_pEditor->GetControl() ) {
    return;
  }
  M_Code_StyledTextCtrl* control = m_pEditor->GetControl();
  if( startPos == wxSCI_INVALID_POSITION && endPos == wxSCI_INVALID_POSITION ) {
    startPos = m_MinPos;
    endPos = m_MaxPos;
  }
  m_pTextCtrl->SetBackgroundColour( m_textCtrlBG_Default );
  m_NewPos = control->FindText( fromPos, endPos, m_SearchText, m_flags, &m_LengthFound );
  if( m_NewPos == wxSCI_INVALID_POSITION || m_LengthFound == 0 ) {
    ConfigManager* cfg = Manager::Get()->GetConfigManager( _T( "editor" ) );
    wxColour colourTextCtrlBG_Wrapped( cfg->ReadColour( _T( "/incremental_search/wrapped_colour" ), wxColour( 127, 127, 255 ) ) );
    m_pTextCtrl->SetBackgroundColour( colourTextCtrlBG_Wrapped );
    m_NewPos = control->FindText( startPos, endPos, m_SearchText, m_flags, &m_LengthFound );
    if( m_NewPos == wxSCI_INVALID_POSITION  || m_LengthFound == 0 ) {
      wxColour colourTextCtrlBG_NotFound( cfg->ReadColour( _T( "/incremental_search/text_not_found_colour" ), wxColour( 255, 127, 127 ) ) );
      m_pTextCtrl->SetBackgroundColour( colourTextCtrlBG_NotFound );
    }
  }
}

void IncrementalSearch::OnMenuEditPaste( wxCommandEvent& event ) {
  if( !IsAttached() ) {
    event.Skip();
    return;
  }
  wxWindow* pFocused = wxWindow::FindFocus();
  if( !pFocused ) {
    event.Skip();
    return;
  }
  if( pFocused == m_pTextCtrl ) {
    m_pTextCtrl->Paste();
  } else {
    event.Skip();
  }
}
